package com.ifd.gui;

import java.awt.Event;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Hashtable;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JMenuItem;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;

public class UndoHandler implements UndoableEditListener {
	private UndoManager undoManager;
	private Hashtable<String, Object> componentManager;
	private UndoAction undoAction = null;
	private RedoAction redoAction = null;

	public UndoHandler(UndoManager undoManager, 
			Hashtable<String, Object> componentManager) {
		this.undoManager=undoManager;
		this.componentManager = componentManager;
		KeyStroke undoKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_Z, Event.META_MASK);
		KeyStroke redoKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_Y, Event.META_MASK);
		
		JTextArea textArea = (JTextArea)componentManager.get("text_area"); 
		undoAction = new UndoAction();
		textArea.getInputMap().put(undoKeystroke, "undoKeystroke");
		textArea.getActionMap().put("undoKeystroke", undoAction);
		((JMenuItem)componentManager.get("edit.undo")).setAction(undoAction);
		((JMenuItem)componentManager.get("edit.undo")).setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z,
				ActionEvent.CTRL_MASK));

		redoAction = new RedoAction();
		textArea.getInputMap().put(redoKeystroke, "redoKeystroke");
		textArea.getActionMap().put("redoKeystroke", redoAction);
		((JMenuItem)componentManager.get("edit.redo")).setAction(redoAction);
		((JMenuItem)componentManager.get("edit.redo")).setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y,
				ActionEvent.CTRL_MASK));
	}
	public void undoableEditHappened(UndoableEditEvent e) {
		//Remember the edit and update the menus
		undoManager.addEdit(e.getEdit());
	    undoAction.update();
	    redoAction.update();
	}
	
	class UndoAction extends AbstractAction
	  {
		  public UndoAction()
		  {
		    super("Undo");
		    setEnabled(false);
		  }

		  public void actionPerformed(ActionEvent e)
		  {
		    try
		    {
		      undoManager.undo();
		    }
		    catch (CannotUndoException ex)
		    {
		    }
		    update();
		    redoAction.update();
		  }

		  protected void update()
		  {
		    if (undoManager.canUndo())
		    {
		      setEnabled(true);
//		      putValue(Action.NAME, undoManager.getUndoPresentationName());
		    }
		    else
		    {
		      setEnabled(false);
//		      putValue(Action.NAME, "Undo");
		    }
		  }
		}

		class RedoAction extends AbstractAction
		{
		  public RedoAction()
		  {
		    super("Redo");
		    setEnabled(false);
		  }

		  public void actionPerformed(ActionEvent e)
		  {
		    try
		    {
		      undoManager.redo();
		    }
		    catch (CannotRedoException ex)
		    {
		      // TODO deal with this
		      ex.printStackTrace();
		    }
		    update();
		    undoAction.update();
		  }

		  protected void update()
		  {
		    if (undoManager.canRedo())
		    {
		      setEnabled(true);
//		      putValue(Action.NAME, undoManager.getRedoPresentationName());
		    }
		    else
		    {
		      setEnabled(false);
//		      putValue(Action.NAME, "Redo");
		    }
		  }
}
}